package com.acme.javaschool.intense.sems.sem2concurrency.computing;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Brutal. No fancy optimisation.
 */
public class SlowpokeMathematician implements Computable<Integer, List<Integer>>{
	private int count;
    private List<Integer> primes;

	public SlowpokeMathematician() {
		count = 0;
        primes = new ArrayList<>();
    }

	public List<Integer> getFactors(int n) {
        if (n < 1) {
            throw new RuntimeException("Gotta factorize positive values, which " + n + " definitely isn't.");
        } else if (n == 1) {
            throw new RuntimeException("What's WRONG with you? :( It's 1.");
        }
        List<Integer> factors = new ArrayList<>();
        if ((primes.size() == 0) || (primes.get(primes.size() - 1) < n / 2)) {
            findPrimes(n / 2);
        }

		for (int prime : primes) {
            while (n % prime == 0) {
                factors.add(prime);
                n /= prime;
            }
        }
        return factors;
	}
	
	private void findPrimes(int n) {
        primes = new ArrayList<>(); //machines are here to work! >:o

        int[] numbers = new int[n + 1];
        byte[] deleted = new byte[n + 1];

        for (int i = 0; i <= n; i++) {
            numbers[i] = i;
            deleted[i] = 0;
        }

        for (int i = 2; i <= n; i++) {
            if (deleted[i] == 0) {
                int num = numbers[i];

                for (int j = num; j <= n; j += num) {
                    deleted[j] = 1;
                }
                primes.add(num);
            }
        }
	}

    public List<Integer> getPrimes() {
        return Collections.unmodifiableList(primes);
    }

    public List<Integer> getPrimes(int n) {
        findPrimes(n);
        return getPrimes();
    }

    @Override
	public int getCount() {
		return count;
	}

    @Override
	public void reset() {
		count = 0;		
	}

    @Override
    public List<Integer> compute(Integer arg) throws InterruptedException {
        count++;
        return getFactors(arg);
    }
}